﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Micro.Extensions.Utilities;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace Micro.Extensions.Bridge
{
    /// <summary>
    /// 服务调用
    /// </summary>
    public class Bridge : IBridge
    {
        private readonly IServiceManager _serviceManager;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ILogger _logger;
        public Bridge(IServiceManager serviceManager,
            IHttpContextAccessor httpContextAccessor,
            ILogger<Bridge> logger)
        {
            _serviceManager = serviceManager;
            _httpContextAccessor = httpContextAccessor;
            _logger = logger;
        }


        public async Task<string> GetStringAsync(string serviceName, string api, Dictionary<string, string> headers = null)
        {
            HttpClient httpClient = null;

            try
            {
                httpClient = await _serviceManager.GetHttpClientAsync(serviceName).ConfigureAwait(false);
                ConfigHttpClientHeaders(httpClient, headers);

                _logger.LogBridgeDebug("GetStringAsync 请求, api: {0}{1}, headers: {2}", httpClient?.BaseAddress, api, httpClient.DefaultRequestHeaders?.ToJson());
                return await httpClient.GetStringAsync(api);
            }
            catch (Exception ex)
            {
                var message = $"HTTP GET 请求 {httpClient?.BaseAddress}{api} 地址错误";
                _logger.LogBridgeError(ex, message);
                throw;
            }
        }

        public async Task<T> GetAsync<T>(string serviceName, string api, Dictionary<string, string> headers = null)
        {
            var response = await GetStringAsync(serviceName, api, headers);
            return response.FromJsonToObj<T>();
        }

        public async Task<HttpResponseMessage> GetResponseAsync(string serviceName, string api, Dictionary<string, string> headers = null)
        {
            HttpClient httpClient = null;

            try
            {
                httpClient = await _serviceManager.GetHttpClientAsync(serviceName).ConfigureAwait(false);
                ConfigHttpClientHeaders(httpClient, headers);

                _logger.LogDebug("PostResponseAsync 请求, api: {0}, headers: {1}", api, httpClient.DefaultRequestHeaders?.ToJson());
                return await httpClient.GetAsync(api);
            }
            catch (Exception ex)
            {
                var message = $"HTTP GET 请求 {httpClient?.BaseAddress}{api} 地址错误";
                _logger.LogBridgeError(ex, message);
                throw;
            }
        }

        public async Task<T> PostAsync<T>(string serviceName, string api, string jsonContent, Dictionary<string, string> headers = null)
        {
            HttpClient httpClient = null;

            try
            {
                httpClient = await _serviceManager.GetHttpClientAsync(serviceName).ConfigureAwait(false);
                ConfigHttpClientHeaders(httpClient, headers);

                _logger.LogBridgeDebug("PostAsync 请求, api: {0}{1}, content: {2}, headers: {3}", httpClient?.BaseAddress, api, jsonContent ?? string.Empty, httpClient.DefaultRequestHeaders?.ToJson());
                var response = await httpClient.PostAsync(api, new StringContent(jsonContent ?? string.Empty, Encoding.UTF8, "application/json"));

                response.EnsureSuccessStatusCode();
                var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                return responseString.FromJsonToObj<T>();
            }
            catch (Exception ex)
            {
                var message = $"HTTP POST 请求 {httpClient?.BaseAddress}{api} 错误";
                _logger.LogBridgeError(ex, message);
                throw;
            }
        }

        public async Task<HttpResponseMessage> PostResponseAsync(string serviceName, string api, string jsonContent, Dictionary<string, string> headers = null)
        {
            HttpClient httpClient = null;

            try
            {
                httpClient = await _serviceManager.GetHttpClientAsync(serviceName).ConfigureAwait(false);
                ConfigHttpClientHeaders(httpClient, headers);

                _logger.LogDebug("PostResponseAsync 请求, api:{0}, content:{1}, headers: {2}", api, jsonContent ?? string.Empty, httpClient.DefaultRequestHeaders?.ToJson());
                return await httpClient.PostAsync(api, new StringContent(jsonContent ?? string.Empty, Encoding.UTF8, "application/json"));
            }
            catch (Exception ex)
            {
                var message = $"HTTP POST 请求 {httpClient?.BaseAddress}{api} 错误";
                _logger.LogBridgeError(ex, message);
                throw;
            }
        }

        public async Task<T> PutAsync<T>(string serviceName, string api, string jsonContent, Dictionary<string, string> headers = null)
        {
            HttpClient httpClient = null;

            try
            {
                httpClient = await _serviceManager.GetHttpClientAsync(serviceName).ConfigureAwait(false);
                ConfigHttpClientHeaders(httpClient, headers);
                _logger.LogDebug("PutAsync 请求, api:{0}, content:{1}, headers: {2}", api, jsonContent ?? string.Empty, httpClient.DefaultRequestHeaders?.ToJson());
                var response = await httpClient.PutAsync(api, new StringContent(jsonContent ?? string.Empty, Encoding.UTF8, "application/json"));

                response.EnsureSuccessStatusCode();
                var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                return responseString.FromJsonToObj<T>();
            }
            catch (Exception ex)
            {
                var message = $"HTTP PUT 请求 {httpClient?.BaseAddress}{api} 错误";
                _logger.LogBridgeError(ex, message);
                throw;
            }
        }

        public async Task<T> DeleteAsync<T>(string serviceName, string api, Dictionary<string, string> headers = null)
        {
            HttpClient httpClient = null;

            try
            {
                httpClient = await _serviceManager.GetHttpClientAsync(serviceName).ConfigureAwait(false);
                ConfigHttpClientHeaders(httpClient, headers);

                _logger.LogBridgeDebug("DeleteAsync 请求, api: {0}{1}, headers: {2}", httpClient?.BaseAddress, api, httpClient.DefaultRequestHeaders?.ToJson());
                var response = await httpClient.DeleteAsync(api);

                response.EnsureSuccessStatusCode();
                var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                return responseString.FromJsonToObj<T>();
            }
            catch (Exception ex)
            {
                var message = $"HTTP DELETE 请求 {httpClient?.BaseAddress}{api} 错误";
                _logger.LogBridgeError(ex, message);
                throw;
            }
        }

        public async Task<HttpResponseMessage> SendAsync(string serviceName, HttpRequestMessage request, Dictionary<string, string> headers = null)
        {
            HttpClient httpClient = null;

            try
            {
                httpClient = await _serviceManager.GetHttpClientAsync(serviceName).ConfigureAwait(false);
                ConfigHttpClientHeaders(httpClient, headers);

                _logger.LogBridgeDebug("SendAsync 请求, api: {0}, request: {2}", request.RequestUri.AbsoluteUri, request.ToJson());
                return await httpClient.SendAsync(request);
            }
            catch (Exception ex)
            {
                var message = $"HTTP SEND 请求 {httpClient?.BaseAddress} 错误, request: {request.ToJson()}";
                _logger.LogBridgeError(ex, message);
                throw;
            }
        }

        private void ConfigHttpClientHeaders(HttpClient httpClient, Dictionary<string, string> headers = null)
        {
            var requestHeaders = _httpContextAccessor?.HttpContext?.Request?.Headers;
            if (requestHeaders != null)
            {
                foreach (var header in requestHeaders) //传递所有默认http header
                {
                    if (header.Key != "Accept" && header.Key != "Accept-Encoding" && header.Key != "Accept-Charset")
                        httpClient.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value.ToString());
                }
            }

            if (headers != null)
            {
                foreach (var header in headers) //加载方法header
                {
                    if (httpClient.DefaultRequestHeaders.Contains(header.Key)) //如果key冲突，以方法header 为主
                        httpClient.DefaultRequestHeaders.Remove(header.Key);

                    httpClient.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);
                }
            }
        }
    }
}
